<?php
namespace app\common\service;

use think\facade\Db;
use think\facade\Filesystem;
use think\facade\Request;
use think\Response;

class FileSync extends Base
{
    static $AUTH_CHECK = false; //默认必须登录
    /**
     * 比对文件差异
     * @param array $fileList 待比对的文件列表
     * @return array
     */
    public function compareFiles()
    {
        writeLog('收到请求','filesync');
        $fileList = input('file_list/a');
//        $fileList = json_decode($fileList, true);
//        writeLog('收到请求文件数量'.count($fileList),'filesync');
//        writeLog('收到请求数据'.json_encode(input()),'filesync');
        if (empty($fileList)) {
            //throw new \Exception('文件列表不能为空');
            return [
                'status'=>0,
                'msg' => '文件列表不能为空',
            ];
        }
        $authkey = input('authkey');
        $domain = input('domain');
        $res_auth = $this->validateAuth($authkey,$domain);
//        writeLog('授权验证'.json_encode($res_auth),'filesync');
        if(!$res_auth['status']){
            return $res_auth;
        }
        $missingFiles = [];
        $modifiedFiles = [];
        $newFiles = [];
        $basePath = root_path();
        $token = input('token');
        $token_plugins_code = [];


        // 获取所有本地文件
        $localFiles = [];
        $this->scanDirectory($basePath, $localFiles);
//        writeLog('扫描文件','filesync');
        // 检查远程文件列表
        foreach ($fileList as $file) {
            if(!isset($localFiles[$file['path']])){
                continue;
            }
            $filePath = $basePath . $file['path'];
            if (!file_exists($filePath)) {
                $missingFiles[] = [
                    'path' => $file['path'],
                    'md5' => $file['md5'],
                    'type' => 'missing',
                    'download_url' => ''
                ];
                continue;
            }

            $localMd5 = $localFiles[$file['path']]['md5'];
            if ($localMd5 !== $file['md5']) {
                $modifiedFiles[] = [
                    'path' => $file['path'],
                    'md5' => $file['md5'],
                    'type' => 'modified',
                    'download_url' => url('api/FileSync/download', ['file' => $file['path']], true, true)
                ];
            }

            // 标记已检查的文件
            unset($localFiles[$file['path']]);
        }

        // 剩余的本地文件即为新增文件
        foreach ($localFiles as $path => $file) {
            $newFiles[] = [
                'path' => $path,
                'type' => 'new',
                'md5' => $file['md5'],
                'download_url' => url('api/FileSync/download', ['file' => $path], true, true)
            ];
        }
        writeLog('返回内容'.count($missingFiles).'=>'.count($modifiedFiles).'=>'.count($newFiles),'filesync');
        return [
            'status'=>1,
            'missing' => $missingFiles,
            'modified' => $modifiedFiles,
            'new' => $newFiles
        ];
    }

    /**
     * 扫描目录获取所有文件
     * @param string $dir 目录路径
     * @param array &$files 文件列表
     * @param string $base 基础路径
     */
    protected function scanDirectory(string $dir, array &$files, string $base = '')
    {
        $excludes = [
            ROOT_PATH.'.git',
            ROOT_PATH.'.idea',
            ROOT_PATH.'runtime',
            ROOT_PATH.'public/upload',
            ROOT_PATH.'install.php',
            ROOT_PATH.'public/install',
            ROOT_PATH.'public/.user.ini',
            ROOT_PATH.'.env',
            ROOT_PATH.'.example.env',
            ROOT_PATH.'.gitignore',
            ROOT_PATH.'app/.htaccess',
            ROOT_PATH.'env.php',
            ROOT_PATH.'app/common/service/FileSync.php',
            ROOT_PATH.'app/common/service/Install.php',
            ROOT_PATH.'app/common/service/Install.php',
//            ROOT_PATH.'admin/controller/Upgrade.php',
            ROOT_PATH.'public/static/design_page/fonts/msyh.ttf',
            ROOT_PATH.'basic/basic_old'

        ];
//        writeLog('忽略文件'.json_encode($excludes,JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES + JSON_NUMERIC_CHECK),'filesync');
        $files = [];
        $path = rtrim($dir, '/');

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $relativePath = str_replace($path, '', $file->getPathname());
//                writeLog('文件路径'.str_replace('\\', '/', $file->getPathname()),'filesync');
                // 检查是否在排除列表中
                $exclude = false;
                foreach ($excludes as $pattern) {
                    // 统一使用正斜杠处理路径
                    $pattern = str_replace('\\', '/', $pattern);
                    $currentPath = str_replace('\\', '/', $file->getPathname());

                    // 检查文件是否在排除目录下
                    if (strpos($currentPath, $pattern) === 0) {
                        $exclude = true;
                        break;
                    }
                }
                if(pathinfo($file->getPathname(), PATHINFO_EXTENSION) === 'zip'){
                    //过滤压缩文件
                    continue;
                }

                if (!$exclude) {
                    // 读取文件内容并去除顶部注释
//                    $content = file_get_contents($file->getPathname());
//                    if (strpos( $file->getPathname(), 'app' . DIRECTORY_SEPARATOR) !== false && pathinfo( $file->getPathname(), PATHINFO_EXTENSION) === 'php'){
//                        $content = preg_replace('/^\s*<\?php\s*(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/|(\/\/.*[\r\n])+)/', '<?php', $content);
//                    }
                    $files[$relativePath] = [
                        'path' => $relativePath,
                        'md5' => md5_file($file->getPathname())
                    ];
                }
            }
        }

        return $files;
    }
    

    /**
     * 处理文件下载请求
     * @return Response
     */
    public function download()
    {
        //header('HTTP/1.1 401 Unauthorized');
        $authkey = input('authkey');
        $domain = input('domain');
        writeLog('请求参数'.json_encode(input()),'download_file');
        $res_auth = $this->validateAuth($authkey,$domain);
        if(!$res_auth['status']){
            return $res_auth;
        }
        try {

            //生成授权信息
            $auth_text = '/**
 * UniTpShop（www.unitpshop.com） - 微信公众号小程序商城系统!
 * Copyright © 2025 www.unitpshop.com 保留所有权利
 * =========================================================
 * 版本：1.0
 * 授权主体：'.cache('auth_domain_'.$domain).'
 * 授权域名：'.$domain.'
 * 授权码：'.$authkey.'
 * ----------------------------------------------
 * 您只能在商业授权范围内使用，不可二次转售、分发、分享、传播
 * 任何企业和个人不得对代码以任何目的任何形式的再发布
 * =========================================================
 */';

            $file = Request::get('file');
            $md5 = Request::get('md5');
            $filePath = $this->getFilePath($file, $md5);
            
            if (!file_exists($filePath)) {
                return json(['code' => 0, 'msg' => '文件不存在'])
                    ->header([
                        'HTTP/1.1' => '404 Not Found',
                        'Content-Type' => 'application/json; charset=utf-8'
                    ]);
            }
            // 直接输出文件内容
            header('HTTP/1.1 200 OK');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="' . basename($file) . '"');
            header('Content-Length: ' . filesize($filePath));
            header('Cache-Control: no-cache');
            header('Pragma: no-cache');
            header('Connection: keep-alive');
            
            if (strpos($filePath, 'app'. DIRECTORY_SEPARATOR) !== false && pathinfo($filePath, PATHINFO_EXTENSION) === 'php') {
                //php文件写入授权信息
                $content = file_get_contents($filePath);
                // 查找PHP开始标记
                $phpStartPos = strpos($content, '<?php');
                if ($phpStartPos !== false) {
                    // 在PHP标记后插入授权信息
                    $content = substr_replace($content, "\n" . $auth_text . "\n", $phpStartPos + 5, 0);
                } else {
                    // 如果没有找到PHP标记，直接在开头添加
                    $content = $auth_text . "\n" . $content;
                }
                header('Content-Length: ' . strlen($content));
                echo $content;
            } else {
                readfile($filePath);
            }
            exit;
            
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => $e->getMessage()]);
        }
    }

    /**
     * 获取文件路径
     * @param string $file 文件路径
     * @return string 文件完整路径
     * @throws \Exception
     */
    protected function getFilePath(string $file, ?string $md5 = null)
    {
        if (empty($file)) {
            throw new \Exception('文件参数不能为空');
        }

        // 安全检查：防止目录遍历
        $file = str_replace(['../', '..\\'], '', $file);
        $filePath = root_path() . $file;

        if (!file_exists($filePath)) {
            throw new \Exception('文件不存在');
        }

        // 如果提供了MD5，验证文件完整性
        if ($md5 !== null) {
            $actualMd5 = md5_file($filePath);
            if ($actualMd5 !== $md5) {
                writeLog('请求参数'.$actualMd5.'=='.$md5,'download_file');
                //throw new \Exception('文件校验失败');
            }
        }

        return $filePath;
    }

    public function validateAuth($authkey,$domain){
        if(cache('auth_domain_'.$domain)){
            return [
                'status'=>1,
                'msg' => '授权成功',
            ];
        }
        $auth = Db::name('auth_domain')
            ->where('auth_code',$authkey)
            ->where('domain',$domain)
            ->find();
        $sql = Db::getLastSql();
        writeLog('授权查询'.$sql,'download_file');
        if(!$auth){
            return [
                'status'=>0,
                'msg' => '未授权',
            ];
        }
        if($auth['type']==1){
            //临时授权
            $end_time = $auth['w_time']+86400*7;
            if($end_time<time()){
                return [
                    'status'=>0,
                    'msg' => '临时授权已过期',
                ];
            }
        }else{
            if($auth['beian']==0){
                return [
                    'status'=>0,
                    'msg' => '域名未备案',
                ];
            }
            if($auth['status']==0){
                return [
                    'status'=>0,
                    'msg' => '未授权',
                ];
            }
        }
        cache('auth_domain_'.$domain,$auth['name'],3600);
        return [
            'status'=>1,
            'msg' => '授权成功',
        ];
    }


    public function check_domain(){
        $domain = input('domain');
        //检测域名是否授权
        $domain_path = pathinfo($domain);
        $domain = $domain_path['basename'];
        $exit = Db::name('auth_domain')->where('domain',$domain)->find();
        $log = [];
        $log['domain'] = $domain;
        $log['w_time'] = time();
        if(!$exit){
            //未授权的自动生成授权码，并给与一周使用时间
            $data = [];
            $data['domain'] = $domain;
            $data['name'] = '临时';
            $data['remark'] = '临时一周权限';
            $data['w_time'] = time();
            $data['type'] = 1;
            $rs = Db::name('auth_domain')->insert($data);
            $auth = ['type'=>1,'end_time'=>time()+7*86400];
            return ['status'=>true,'msg'=>'','auth'=>$auth];
        }else{
            if($exit['status']==0){
                $res = ['status'=>false,'msg'=>'域名未授权或已过期'];
            }else{
                $res = ['status'=>true,'msg'=>'已授权'];
            }

        }
        if($exit['type']==1){
            //临时授权只检测有效期，暂时不检测域名
            $end_time = $exit['w_time']+7*86400;
            if(time()>$end_time){
                $res = ['status'=>false,'msg'=>'授权已过期'];
            }
            $auth = ['type'=>1,'end_time'=>time()+7*86400];
            return ['status'=>true,'msg'=>'','auth'=>$auth];
        }
        $log['msg'] = $res['msg'];
        $check_time = time()-30*86400;//每月检测一次备案
        $cache = cache('check_beian_'.$domain);
        if($exit && ($exit['beian']==0 || $exit['beian_check_time']<=$check_time) && $cache!=1 && $res['status']){
            $res_beian = $this->check_beian($domain);
            Db::name('auth_domain')->where('domain',$domain)->update([
                'beian'=>$res_beian['status']?1:0,
                'beian_check_time'=>time(),
                'beian_msg'=>$res_beian['beian_result']??'',
                'beian_no'=>$res_beian['msg']??''
            ]);
            $res = $res_beian;
            $log['msg'] = $res_beian['msg'];
        }
        Db::name('auth_domain_log')->insert($log);
        //授权信息
        $res['auth'] = ['type'=>0,'end_time'=>0];
        $update = [
            'need_update' => 0,
            'new_version' => '',
            'update_text' => '',
            'update_time' => ''
        ];
        if(input('version')){
            //更新信息
            $last_version = Db::name('forum')->where('type','update')->order('id desc')->find();
            $update['new_version'] = $last_version['version'];
            $update['update_text'] = $last_version['content'];
            $update['update_time'] = date('Y-m-d H:i:s',$last_version['create_time']);
            if($last_version['version']!=input('version')){
                $update['need_update'] = 1;
            }
        }
        $res['update'] = $update;
        return $res;
    }
    public function check_beian($domain){
        $url = 'https://api.leafone.cn/api/icp?name='.$domain;
        $res = request_get($url);
        $res = json_decode($res,true);
        cache('check_beian_'.$domain,1,86400);
        if($res['code']==200 ){
            $list = $res['data']['list']??[];
            if(!empty($list[0]['mainLicence'])){
                return ['status'=>true,'msg'=>$list[0]['mainLicence'],'beian_result'=>json_encode($res)];
            }else{
                return ['status'=>false,'msg'=>'查询备案失败'];
            }
        }else{
            return ['status'=>false,'msg'=>$res['msg']];
        }
    }
    public function check_beian2($domain){
        // https://www.mxnzp.com/console/user-info
        //fgsjlpmvgqnomnkd
        //KavGRjwKdXzaIg4hbOfaXqcuUsQ8PIHT
        $app_id = 'fgsjlpmvgqnomnkd';
        $app_secret = 'KavGRjwKdXzaIg4hbOfaXqcuUsQ8PIHT';
        dump($domain);
        $url = 'https://www.mxnzp.com/api/beian/search?app_id='.$app_id.'&app_secret='.$app_secret.'&domain='.base64_encode($domain);
        dump($url);
        $res = request_get($url);
        $res = json_decode($res,true);
        dump($res);exit;
        if($res['code']==1 && !empty($res['data']['icpCode'])){
            return ['status'=>true,'msg'=>$res['data']['icpCode']];
        }else{
            return ['status'=>false,'msg'=>$res['msg']];
        }
        //检测域名是否备案
        //聚合api https://www.juhe.cn/docs/api/id/439
        $url = 'http://v.juhe.cn/siteTools/app/NewDomain/query.php';
        $data = [
            'domainName' => $domain,
            'key' => '',
        ];
        $res = curl_post($url,$data);
        $res = json_decode($res,true);
        $SiteLicense = '';
        if($res['error_code']!=0){
            $SiteLicense = $res['result']['SiteLicense'];
        }
        //一天只查询一次
        cache('check_beian_'.$domain,1,86400);

        if(!$SiteLicense){
            return ['status'=>false,'msg'=>'未备案'];
        }else{
            return ['status'=>true,'msg'=>$SiteLicense];
        }
    }
}